<template>
  <div class="gantt-timeline">
    <div
        class="gantt-timeline-padding_block"
        :style="{ width: paddingWidth + 'px' }"
    ></div>
    <template v-for="(day, index) in allDayBlocks" :key="index">
      <div
          class="gantt-timeline-block"
          :style="{ width: getTimeScales(day).length * cellWidth + 'px' }"
      >
        <slot :day="day" :getTimeScales="getTimeScales">
          <div class="gantt-timeline-day" :style="heightStyle">
            {{ format(day, "yy/MM/dd") }}
          </div>
          <div
              v-if="!isDayScale"
              class="gantt-timeline-scale"
              :style="heightStyle"
          >
            <div
                v-for="(time, index) in getTimeScales(day)"
                :key="index"
                :style="cellWidthStyle"
            >
              {{ scale >= 60 ? format(time, "HH") : format(time, "HH:mm") }}
            </div>
          </div>
        </slot>
      </div>
    </template>
  </div>
</template>

<script lang="ts" setup>
import {computed, PropType} from 'vue';
import dayjs from 'dayjs';
import {
  addDays,
  startOfDay,
  endOfDay,
  isBefore,
  isAfter,
  isEqual,
  isSameDay,
  format,
  parseISO,
  intervalToDateArray,
  isWithinInterval,
  subDays,
  addMinutes
} from 'date-fns';

import {
  isDayScale as _isDayScale,
  MINUTE_OF_ONE_DAY,
  getBeginTimeOfTimeLine
} from '@/utils/timeLineUtils.ts';

const START_DAY = Symbol();
const MIDDLE_DAY = Symbol();
const END_DAY = Symbol();

const props = defineProps({
  start: {
    type: Object as PropType<dayjs.Dayjs>,
    required: true
  },
  end: {
    type: Object as PropType<dayjs.Dayjs>,
    required: true
  },
  cellWidth: {
    type: Number,
    required: true
  },
  titleHeight: {
    type: Number,
    required: true
  },
  scale: {
    type: Number,
    required: true
  },
  endTimeOfRenderArea: [Object as PropType<dayjs.Dayjs> | null, null],
  startTimeOfRenderArea: [Object as PropType<dayjs.Dayjs> | null, null],
  getPositionOffset: {
    type: Function as PropType<(date: string) => number>,
    required: true
  },
  currentTime: {
    type: Object as PropType<dayjs.Dayjs>,
    required: true
  }
});


const startDayOfRenderArea = computed(() => {
  return props.startTimeOfRenderArea ? startOfDay(new Date(props.startTimeOfRenderArea)) : new Date();
});

const endDayOfRenderArea = computed(() => {
  return props.endTimeOfRenderArea ? endOfDay(new Date(props.endTimeOfRenderArea)) : new Date();
});


const paddingWidth = computed(() => {
  const { scale } = props;
  const temp = allDayBlocks.value.find((day) => {
    const dayStart = startOfDay(new Date(day));
    const dayEnd = addDays(dayStart, _isDayScale(scale) ? Math.ceil(scale / MINUTE_OF_ONE_DAY) : 1);
    return isEqual(startDayOfRenderArea.value, dayStart) || isWithinInterval(startDayOfRenderArea.value, dayStart, dayEnd);
  });
  if (!temp || temp === allDayBlocks.value[0]) {
    return 0;
  } else {
    // 假设 getPositionOffset 接受一个日期对象并返回偏移量（这里需要您根据实际情况调整）
    return props.getPositionOffset(temp); // 注意：这里可能需要调整以接受日期对象或转换为字符串
  }
});

// const paddingWidth = computed(() => {
//   const {scale} = props;
//   const temp = allDayBlocks.value.find((day) => {
//     if (
//         scale >= MINUTE_OF_ONE_DAY &&
//         startDayOfRenderArea.value.isBetween(
//             day,
//             day.add(scale / MINUTE_OF_ONE_DAY, 'day')
//         )
//     ) {
//       return true;
//     } else {
//       return day.isSame(startDayOfRenderArea, 'day');
//     }
//   });
//   if (!temp || temp === allDayBlocks.value[0]) {
//     return 0;
//   } else {
//     return props.getPositionOffset(temp.toString());
//   }
// });

const isDayScale = computed(() => _isDayScale(props.scale));

const allDayBlocks = computed(() => {
  const temp = [];
  let { start, end, scale } = props;
  start = startOfDay(new Date(start));
  end = endOfDay(new Date(end));
  let addNum = _isDayScale(scale) && scale > MINUTE_OF_ONE_DAY ? Math.ceil(scale / MINUTE_OF_ONE_DAY) : 1;
  while (isBefore(start, end) || isEqual(start, end)) {
    temp.push(start);
    start = addDays(start, addNum);
  }
  return temp.map(date => date.toISOString()); // 转换为 ISO 字符串以便在模板中使用（如果需要）
});

const cellWidthStyle = computed(() => ({
  width: `${props.cellWidth}px`
}));

const heightStyle = computed(() => ({
  height: props.titleHeight / (isDayScale.value ? 1 : 2) + 'px',
  lineHeight: props.titleHeight / (isDayScale.value ? 1 : 2) + 'px'
}));


// const isInRenderingDayRange = (day: dayjs.Dayjs) => {
//   // 暂时废弃
//   const {scale, currentTime} = props;
//   // let preDay = currentTime.subtract(1, 'day')
//   // let nextDay = currentTime.add(1, 'day')
//   if (
//       scale >= MINUTE_OF_ONE_DAY &&
//       startDayOfRenderArea.value.isBetween(
//           day,
//           day.add(scale / MINUTE_OF_ONE_DAY, 'day')
//       )
//   ) {
//     return true;
//   } else {
//     return startDayOfRenderArea.value.isSameOrBefore(day) && endDayOfRenderArea.value.isSameOrAfter(day);
//   }
// };

const getTimeScales = (date: string) => {
  const parsedDate = parseISO(date);
  if (isSameDay(parsedDate, new Date(props.start))) {
    return generateTimeScale(START_DAY, parsedDate);
  } else if (isSameDay(parsedDate, new Date(props.end))) {
    return generateTimeScale(END_DAY, parsedDate);
  } else {
    return generateTimeScale(MIDDLE_DAY, parsedDate);
  }
};

const generateTimeScale = (type: symbol, date: Date): Date[] => {
  const { start, end, scale } = props;
  let a, b;
  const parsedStart = new Date(start);
  const parsedEnd = new Date(end);

  switch (type) {
    case START_DAY:
      a = getBeginTimeOfTimeLine(dayjs(parsedStart), scale); // 这里我们假设它返回了一个 Date 对象
      b = isSameDay(parsedStart, parsedEnd) ? parsedEnd : endOfDay(parsedStart);
      break;
    case END_DAY:
      a = startOfDay(parsedEnd);
      b = parsedEnd;
      break;
    case MIDDLE_DAY:
      a = startOfDay(date);
      b = endOfDay(date);
      break;
    default:
      throw new TypeError('错误的计算类型');
  }

  const totalBlock: Date[] = [];
  let currentTime = a;
  while (isBefore(currentTime, b) || isEqual(currentTime, b)) {
    totalBlock.push(new Date(currentTime));
    currentTime = addMinutes(currentTime, scale);
  }
  return totalBlock;
};
</script>

<style scoped lang="scss">
/* 您的样式代码 */

.gantt-timeline-day {
  overflow: hidden;
  font-weight: bold;
  color: #666;
  border-right: 1px solid #aaa;
  border-bottom: 1px solid #ddd;
}

.gantt-timeline-scale {
  display: flex;
  border-right: 1px solid #aaa;

  & > div {
    height: 100%;
    font-size: 14px;
    color: #666;
    border-right: 1px solid #ddd;
  }
}
</style>
